import { Matrix4 } from "../../utils/Matrix4";
import { Primitives } from "../../utils/Primitives";
import { TextrueUtil } from "../../utils/TextureUtil";
import { Util } from "../../utils/Util";
import { WebGLUtil } from "../../utils/WebGLUtil";
import { Render } from "../Render";
import { WebglTemplateBase } from "./WebglTemplateBase";

/*
 * @Author: Snow
 * @Date: 2021-10-11 20:35:00
 * @Description: 画多个物体
 */
export class TemplateDrawMore extends WebglTemplateBase {
    protected override initProgram(): void {
        this.vsSource = `
            attribute vec4 a_position;
            attribute vec4 a_color;
            
            uniform mat4 u_matrix;
            
            varying vec4 v_color;
            
            void main() {
                // Multiply the position by the matrix.
                gl_Position = u_matrix * a_position;
                
                // Pass the color to the fragment shader.
                v_color = a_color;
            }
        `;

        this.fsSource = `
            precision mediump float;

            // Passed in from the vertex shader.
            varying vec4 v_color;
            
            uniform vec4 u_colorMult;
            
            void main() {
                gl_FragColor = v_color * u_colorMult;
            }
        `;
        super.initProgram();
    }

    protected override initBuffers(): void {
        super.initBuffers();
        const gl = Render.GL;

        // creates buffers with position, normal, texcoord, and vertex color
        // data for primitives by calling gl.createBuffer, gl.bindBuffer,
        // and gl.bufferData
        //const sphereBufferInfo = Primitives.createSphereWithVertexColorsBufferInfo(gl, 10, 12, 6);
        //   const cubeBufferInfo   = Primitives.createCubeWithVertexColorsBufferInfo(gl, 20);
        //   const coneBufferInfo   = Primitives.createTruncatedConeWithVertexColorsBufferInfo(gl, 10, 0, 20, 12, 1, true, false);
        const sphereBufferInfo = Primitives.createFlattenedFunc(Primitives.createSphereVertices)(gl, 10, 12, 6);

        const cubeBufferInfo = Primitives.createFlattenedFunc(Primitives.createCubeVertices)(gl, 20);
        const coneBufferInfo = Primitives.createFlattenedFunc(Primitives.createTruncatedConeVertices)(gl, 10, 0, 20, 12, 1, true, false);


        //let bufferInfo = WebGLUtil.createBufferInfoFromArrays(gl, arrays);

        let cameraAngleRadians = Util.degToRad(0);
        let fieldOfViewRadians = Util.degToRad(60);
        let cameraHeight = 50;

        // Uniforms for each object.
        let sphereUniforms = {
            u_colorMult: [0.5, 1, 0.5, 1],
            u_matrix: Matrix4.identity(),
        };
        let cubeUniforms = {
            u_colorMult: [1, 0.5, 0.5, 1],
            u_matrix: Matrix4.identity(),
        };
        let coneUniforms = {
            u_colorMult: [0.5, 0.5, 1, 1],
            u_matrix: Matrix4.identity(),
        };
        let sphereTranslation = [0, 0, 0];
        let cubeTranslation = [-40, 0, 0];
        let coneTranslation = [40, 0, 0];


        let textures = [
            TextrueUtil.makeStripeTexture(gl, { color1: "#FFF", color2: "#CCC", }),
            TextrueUtil.makeCheckerTexture(gl, { color1: "#FFF", color2: "#CCC", }),
            TextrueUtil.makeCircleTexture(gl, { color1: "#FFF", color2: "#CCC", }),
        ];

        let objects = [];
        let numObjects = 300;
        let baseColor = Util.rand(240);
        for (var ii = 0; ii < numObjects; ++ii) {
            objects.push({
                radius: Util.rand(150),
                xRotation: Util.rand(Math.PI * 2),
                yRotation: Util.rand(Math.PI),
                materialUniforms: {
                    u_colorMult: [Util.rand(1, 2) / 2, 0.5, 1, 1],
                    u_diffuse: textures[Util.randInt(textures.length)],
                    u_specular: [1, 1, 1, 1],
                    u_shininess: Util.rand(500),
                    u_specularFactor: Util.rand(1),
                },
            });
        }

        let drawScene = () => {
            let time = this.ts;
            time = time * 0.5 + 5;
            WebGLUtil.resizeCanvasToMatchDisplaySize(gl);
            // Clear the canvas AND the depth buffer.
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            // Compute the projection matrix
            let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            var projectionMatrix = Matrix4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            // Compute the camera's matrix using look at.
            let cameraPosition = [0, 0, 100];
            let target = [0, 0, 0];
            let up = [0, 1, 0];
            let cameraMatrix = Matrix4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            let viewMatrix = Matrix4.invert(cameraMatrix);

            let viewProjectionMatrix = Matrix4.multiply(projectionMatrix, viewMatrix);

            let sphereXRotation =  time;
            let sphereYRotation =  time;
            let cubeXRotation   = -time;
            let cubeYRotation   =  time;
            let coneXRotation   =  time;
            let coneYRotation   = -time;

            gl.useProgram(this.programInfo.program);

            let computeMatrix = (viewProjectionMatrix, translation, xRotation, yRotation):number[]=> {
                var matrix = Matrix4.multiply(viewProjectionMatrix,Matrix4.translation(
                    translation[0],
                    translation[1],
                    translation[2]));
                matrix = matrix = Matrix4.multiply(matrix,Matrix4.rotateX(xRotation));
                return matrix = matrix = Matrix4.multiply(matrix,Matrix4.rotateY(yRotation));
              }

            // Setup all the needed buffers and attributes.
            WebGLUtil.setBuffersAndAttributes(gl, this.programInfo, sphereBufferInfo);
            
            sphereUniforms.u_matrix = computeMatrix(viewProjectionMatrix,sphereTranslation,sphereXRotation,sphereYRotation)
            
            // Set the uniforms that are the same for all objects.
            WebGLUtil.setUniforms(this.programInfo, sphereUniforms);

            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES,0,sphereBufferInfo.numElements);
            
            ///立方体
            // Setup all the needed buffers and attributes.
            WebGLUtil.setBuffersAndAttributes(gl, this.programInfo, cubeBufferInfo);
            
            cubeUniforms.u_matrix = computeMatrix(viewProjectionMatrix,cubeTranslation,cubeXRotation,cubeYRotation)
            
            // Set the uniforms that are the same for all objects.
            WebGLUtil.setUniforms(this.programInfo, cubeUniforms);

            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES,0, cubeBufferInfo.numElements);


            ///锥体
            // Setup all the needed buffers and attributes.
            WebGLUtil.setBuffersAndAttributes(gl, this.programInfo, coneBufferInfo);
            
            coneUniforms.u_matrix = computeMatrix(viewProjectionMatrix,coneTranslation,coneXRotation,coneYRotation)
            
            // Set the uniforms that are the same for all objects.
            WebGLUtil.setUniforms(this.programInfo, coneUniforms);

            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES,0, coneBufferInfo.numElements);

        }
        this.draw = drawScene;
    }
}